package sever

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"github.com/elastic/go-elasticsearch/v7/esapi"
	"github.com/robfig/cron/v3"
	"log"
	"strconv"
	"sync"
	"travel-app/common/initialize"
	"travel-app/common/proto/travel"
	"travel-app/pkg"
	"travel-app/rpc/model"
)

func EsSync(in *travel.EsSyncReq) (*travel.EsSyncResp, error) {

	var (
		Travel []*model.Area
		wg     sync.WaitGroup
	)
	initialize.DB.Find(&Travel)

	for _, title := range Travel {
		wg.Add(1)

		go func(Travel *model.Area) {
			defer wg.Done()

			// Build the request body.
			data, err := json.Marshal(&Travel)
			if err != nil {
				log.Fatalf("Error marshaling document: %s", err)
			}

			// Set up the request object.
			req := esapi.IndexRequest{
				Index:      "areas",
				DocumentID: strconv.Itoa(int(Travel.ID)),
				Body:       bytes.NewReader(data),
				Refresh:    "true",
			}

			// Perform the request with the client.
			res, err := req.Do(context.Background(), initialize.Es)
			if err != nil {
				log.Fatalf("Error getting response: %s", err)
			}
			defer res.Body.Close()

		}(title)
	}
	wg.Wait()
	return &travel.EsSyncResp{Success: true}, nil
}
func EsSyncGet(in *travel.EsSyncGetReq) (*travel.EsSyncGetResp, error) {
	var buf bytes.Buffer
	query := map[string]interface{}{}
	if in.Keyword == "" {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"match_all": map[string]interface{}{},
			},
		}
	} else {
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"match": map[string]interface{}{
					"Name": in.Keyword,
				},
			},
		}
	}

	if err := json.NewEncoder(&buf).Encode(query); err != nil {
		log.Fatalf("Error encoding query: %s", err)
	}

	// Perform the search request.
	res, err := initialize.Es.Search(
		initialize.Es.Search.WithContext(context.Background()),
		initialize.Es.Search.WithIndex("areas"),
		initialize.Es.Search.WithBody(&buf),
		initialize.Es.Search.WithTrackTotalHits(true),
		initialize.Es.Search.WithPretty(),
	)
	if err != nil {
		log.Fatalf("Error getting response: %s", err)
	}
	defer res.Body.Close()
	var r map[string]interface{}

	json.NewDecoder(res.Body).Decode(&r)

	var All []*travel.AreaList

	for _, hit := range r["hits"].(map[string]interface{})["hits"].([]interface{}) {
		Source := hit.(map[string]interface{})["_source"].(map[string]interface{})

		goods := &travel.AreaList{
			Name:    Source["Name"].(string),
			Address: Source["Address"].(string),
			Ticket:  float32(Source["Ticket"].(float64)),
			Status:  int64(Source["Status"].(float64)),
			Comment: Source["Comment"].(string),
			Like:    int64(Source["Like"].(float64)),
		}
		All = append(All, goods)
	}

	return &travel.EsSyncGetResp{List: All}, nil
}
func AreaList(in *travel.AreaListReq) (*travel.AreaListResp, error) {
	o := model.Area{}

	area, err := o.FindArea(in.Name)
	if err != nil {
		return nil, fmt.Errorf("景点详情查询失败")
	}

	var all []*travel.AreaList

	for _, a := range area {
		all = append(all, &travel.AreaList{
			Name:    a.Name,
			Address: a.Address,
			Ticket:  float32(a.Ticket),
			Status:  a.Status,
			Comment: a.Comment,
			Like:    int64(a.Like),
		})
	}
	return &travel.AreaListResp{List: all}, nil

}
func BuyTicKet(in *travel.BuyTicKetReq) (*travel.BuyTicKetResp, error) {
	a := model.Area{}
	o := model.Order{}
	u := model.UserReal{}

	area, _ := a.FindAreas(in.AreaId)

	user, err := u.FindUser()
	if err != nil {
		return nil, err
	}
	du := 0
	for _, _ = range user {
		du++
	}

	if in.Sum > int64(du) {
		return nil, fmt.Errorf("购票失败,购票数量和购票人信息数量不一致")
	}

	if area == nil {
		return nil, fmt.Errorf("购票失败,没有该景点信息")
	}

	if in.Sum > area.Stock {
		return nil, fmt.Errorf("购票失败,库存不足")
	}

	order, err := o.CreateTicket(in)

	if err != nil {
		return nil, fmt.Errorf("用户购票失败")
	}

	float := strconv.FormatFloat(order.Price, 'f', -1, 64)

	pay := pkg.NewAlipay().Pay(area.Name, order.OrderSn, float)

	c := cron.New()
	spec := "*/30 * * * * ?"
	_, err = c.AddFunc(spec, func() {
		initialize.DB.Model(&o).Where(o.ID).Update("status", 2)
	})
	fmt.Println(err)
	c.Start()

	return &travel.BuyTicKetResp{
		Success: true,
		Url:     pay,
	}, nil

}

func CallBack(in *travel.PayCallbackReq) (*travel.PayCallbackResp, error) {
	o := model.Order{}

	_, err := o.Update(in)
	if err != nil {
		return nil, err
	}
	return &travel.PayCallbackResp{Success: true}, nil
}

func FindOrder(in *travel.FindOrderReq) (*travel.FindOrderResp, error) {
	order := model.Order{}
	orders, err := order.FindOrder(in.UserID)
	if err != nil {
		return nil, fmt.Errorf("没找到该订单")
	}

	var all []*travel.OrderList
	for _, o := range orders {
		all = append(all, &travel.OrderList{
			ID:           int64(o.ID),
			OrderSn:      o.OrderSn,
			Sum:          o.Sum,
			Price:        float32(o.Price),
			Days:         o.Days,
			TicketStatus: o.TicketStatus,
			Status:       o.Status,
			Insurance:    o.Insurance,
		})
	}
	return &travel.FindOrderResp{List: all}, nil
}
func DelOrder(in *travel.DelOrderReq) (*travel.DelOrderResp, error) {
	o := model.Order{}

	o.DelOrder(in.OrderSn)
	return &travel.DelOrderResp{Success: true}, nil

}
